package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/beevik/etree"
	"strconv"
)

var (
	Stcfg stConfig
)

type stConfig struct {
	BizAddress     string
	QuoteAddress   string
	LoginInterval  uint32
	LoginMaxCount  uint64
	QryFund        uint32
	QryPosition    uint32
	QryGoods       uint32
	QryExch        uint32
	QryOrder       uint32
	QryTrade       uint32
	PrintLog       uint32
	LocalIp        string
	LoginPwdCrypto uint32
	SubscribeQuote uint32
}

func (cfg *stConfig) String() string {
	b, err := json.Marshal(*cfg)
	if err != nil {
		return fmt.Sprintf("%+v", *cfg)
	}

	var out bytes.Buffer

	err = json.Indent(&out, b, "", "    ")
	if err != nil {
		return fmt.Sprintf("%+v", *cfg)
	}

	return out.String()
}

func (cfg *stConfig) BizAddr() string {
	return cfg.BizAddress
}

func xmlReadString(node *etree.Element, nodeName string, dflt string) string {
	elem := node.SelectElement(nodeName)
	if elem == nil {
		return ""
	}

	return elem.SelectAttrValue("value", dflt)
}

func xmlReadInt(node *etree.Element, nodeName string, dflt int) int {
	elem := node.SelectElement(nodeName)
	if elem == nil {
		return dflt
	}

	data := elem.SelectAttrValue("value", strconv.Itoa(dflt))

	nValue, err := strconv.ParseInt(data, 10, 32)
	if err != nil {
		fmt.Println("parse int fail:", err)
	}

	return int(nValue)
}

func stoInt(s string) int {
	nValue, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		fmt.Println("parse int fail:", err)
		return 0
	}
	return int(nValue)
}

func stoUint32(s string) uint32 {
	return uint32(stoInt(s))
}

func getPropertyMap(node *etree.Element, stcfg *stConfig) {

	p := node.SelectElements("property")
	for _, e := range p {

		atrName := e.SelectAttr("name")
		if atrName == nil {
			fmt.Println("read xml select attr name fail.")
			return
		}

		atrV := e.SelectAttr("value")
		if atrV == nil {
			fmt.Println("read xml select attr value fail.")
			return
		}

		switch atrName.Value {
		case "BizAddress":
			stcfg.BizAddress = atrV.Value
		case "QuoteAddress":
			stcfg.QuoteAddress = atrV.Value
		case "LoginInterval":
			stcfg.LoginInterval = uint32(stoInt(atrV.Value))
		case "LoginMaxCount":
			stcfg.LoginMaxCount = uint64(stoInt(atrV.Value))
		case "QryFund":
			stcfg.QryFund = stoUint32(atrV.Value)
		case "QryPosition":
			stcfg.QryPosition = stoUint32(atrV.Value)
		case "QryGoods":
			stcfg.QryGoods = stoUint32(atrV.Value)
		case "QryExch":
			stcfg.QryExch = stoUint32(atrV.Value)
		case "QryOrder":
			stcfg.QryOrder = stoUint32(atrV.Value)
		case "QryTrade":
			stcfg.QryTrade = stoUint32(atrV.Value)
		case "PrintLog":
			stcfg.PrintLog = stoUint32(atrV.Value)
		case "LoginPwdCrypto":
			stcfg.LoginPwdCrypto = stoUint32(atrV.Value)
		case "SubscribeQuote":
			stcfg.SubscribeQuote = stoUint32(atrV.Value)

		}
	}
}

// 导出函数首字母必须大写.
func InitConfig(xmlPath string) {

	// 设置默认值
	Stcfg.PrintLog = 1
	Stcfg.LocalIp = "127.0.0.1"
	Stcfg.LoginPwdCrypto = 0
	Stcfg.SubscribeQuote = 0

	fmt.Println("read config from:", xmlPath)

	xmlDoc := etree.NewDocument()
	if xmlDoc == nil {
		fmt.Println("create etree fail.")
		return
	}

	err := xmlDoc.ReadFromFile(xmlPath)
	if err != nil {
		fmt.Println("read xml file fail:", err)
		return
	}

	root := xmlDoc.SelectElement("configuration")
	if root == nil {
		fmt.Println("read root(configuration) fail.")
		return
	}

	nodes := root.SelectElements("setting")
	if nodes == nil {
		fmt.Println("read nodes(setting) fail.")
		return
	}

	for _, node := range nodes {

		getPropertyMap(node, &Stcfg)
	}
}

func PrintConfig() {
	fmt.Println("---------------config----------------------")
	fmt.Printf("%s\n", Stcfg.String())
	fmt.Println("----------------------------------\n\n")
}
